﻿#ifndef LK_REFCOUNT_//由W意波(LuoJun)编写
#define LK_REFCOUNT_
namespace LK
{
	/**
	@brief 表示一个记录引用次数的对象*/
	struct RefCount
	{
#ifndef WINBASEAPI
#ifdef LK_MUTEX_
	private:
		static SpinMutex& getMutexRef()
		{
			static SpinMutex* p;
			if (p)return *p;
			SpinMutex::GetDefaultRef().Lock();
			static SpinMutex m;
			p = &m;
			SpinMutex::GetDefaultRef().UnLock();
			return m;
		}
#endif
#endif
	public:
		/**
		@brief 获取该引用计数是否启用原子增减
		@return 返回值为true时表示该引用计数启用了原子增减*/
		inline bool GetEnableInterlocked()const { return (index_t)referenceCount < 0; }
		/**
		@brief 设置该引用计数是否使用原子增减
		@param [传入]参数b为true时表示启用原子增减*/
		inline void SetEnableInterlocked(bool b) { if (b)referenceCount |= MinValues::Of((index_t*)NULL); else referenceCount &= MaxValues::Of<index_t>(); }
		//对象引用计数
		mutable volatile size_t referenceCount;
		//被引用计数
		mutable volatile size_t weakReferenceCount;
		/**
		@brief 默认是否默认启用原子增减*/
		static bool& GetDefaultEnableInterlockedRef();
		/**
		@brief 初始化为0*/
		inline RefCount() :referenceCount(GetDefaultEnableInterlockedRef() ? (size_t)MinValues::Of((index_t*)NULL) : 0), weakReferenceCount(1) {}
		/**
		@brief 初始化
		@param [传入]参数v表示引用次数
		@param [传入,可选]参数en表示是否启用互斥*/
		inline RefCount(size_t v, bool en = GetDefaultEnableInterlockedRef()) : referenceCount(v) { SetEnableInterlocked(en); }
		/**
		@brief 转换成数值*/
		inline operator size_t()const { return referenceCount&MaxValues::Of<index_t>(); }
		/**
		@brief 弱引用计数+1*/
		inline size_t AddRef()const
		{
			if (GetEnableInterlocked())
#ifdef WINBASEAPI
#if (_X64==1)
				return (size_t)InterlockedIncrement64((volatile long long*)&weakReferenceCount);
#else
				return (size_t)InterlockedIncrement((volatile long*)&weakReferenceCount);
#endif
#else
#ifdef _LK_MUTEX_
			{
				getMutexRef().Lock();
				size_t t = ++weakReferenceCount;
				getMutexRef().UnLock();
				return t;
			}
#else
				Throw<PException>(L"无法实现引用计数的原子增减");
#endif
#endif
			return ++weakReferenceCount;
		}
		/**
		@brief 弱引用计数-1*/
		inline size_t Release()const
		{
			if (GetEnableInterlocked())
#ifdef WINBASEAPI
#if (_X64==1)
				return (size_t)InterlockedDecrement64((volatile long long*)&weakReferenceCount);
#else
				return (size_t)InterlockedDecrement((volatile long*)&weakReferenceCount);
#endif
#else
#ifdef _LK_MUTEX_
			{
				getMutexRef().Lock();
				size_t t = --weakReferenceCount;
				getMutexRef().UnLock();
				return t;
			}
#else
				Throw<PException>(L"无法实现引用计数的原子增减");
#endif
#endif
			return --weakReferenceCount;
		}
		/**
		@brief 计数+1*/
		inline size_t operator++()const
		{
			if (GetEnableInterlocked())
#ifdef WINBASEAPI
#if (_X64==1)
				return (size_t)InterlockedIncrement64((volatile long long*)&referenceCount) - (size_t)MinValues::Int64;
#else
				return (size_t)InterlockedIncrement((volatile long*)&referenceCount) - (size_t)MinValues::Int32;
#endif
#else
#ifdef _LK_MUTEX_
			{
				getMutexRef().Lock();
				size_t t = ++referenceCount;
				getMutexRef().UnLock();
				return t;
			}
#else
				Throw<PException>(L"无法实现引用计数的原子增减");
#endif
#endif
			return ++referenceCount;
		}
		/**
		@brief 计数-1*/
		inline size_t operator--()const
		{
			if (GetEnableInterlocked())
#ifdef WINBASEAPI
#if (_X64==1)
				return (size_t)InterlockedDecrement64((volatile long long*)&referenceCount) - (size_t)MinValues::Int64;
#else
				return (size_t)InterlockedDecrement((volatile long*)&referenceCount) - (size_t)MinValues::Int32;
#endif
#else
#ifdef _LK_MUTEX_
			{
				getMutexRef().Lock();
				size_t t = --referenceCount;
				getMutexRef().UnLock();
				return t;
			}
#else
				Throw<PException>(L"无法实现引用计数的原子增减");
#endif
#endif
			return --referenceCount;
		}
#ifndef new
#ifdef BLOCKMEMORYALLOC_
		/**
		@biref 当没有定义new来进行内存泄漏检测时，重载operator new*/
		void*operator new(size_t size){ if (size > sizeof(RefCount))ThrowOutOfMemoryException(); return BlockMemory<sizeof(RefCount)>::DefaultPool().Alloc(); }
		void operator delete(void*p) { if (!BlockMemory<sizeof(RefCount)>::DefaultPool().Free(p))ThrowPointerFailureException(); }
		void*operator new[](size_t size) {return ::operator new[](size); }
		void operator delete[](void*p) {::operator delete[](p); }
			/**
			@biref 当没有定义new来进行内存泄漏检测时，重载placement new*/
		void*operator new(size_t, void*p){ return p; }
		void*operator new[](size_t, void*p) {return p; }
#endif
#endif
	private:
		//禁止复制和赋值
		RefCount(const RefCount&);
		RefCount&operator=(RefCount const&);
	};
	/**
	@brief 表示RefCount的引用*/
	struct PRefCount
	{
		//是否启用引用计数的原子增减，同RefCount::GetDefaultEnableInterlockedRef
		static inline bool& GetDefaultEnableInterlockedRef() { return RefCount::GetDefaultEnableInterlockedRef(); }
		//创造引用计数对象，如果引用计数已存在，则直接返回
		inline void Create()const
		{
			if (!pCount)
			{
#ifdef LK_MUTEX_
				getMutexRef().Lock();
#endif
				if (!pCount)pCount = new RefCount();
#ifdef LK_MUTEX_
				getMutexRef().UnLock();
#endif
			}
			return;
		}
		inline PRefCount operator++()const
		{
			Create();
			++*pCount;
			return *this;
		}
		inline PRefCount operator--()const
		{
			if (pCount)--*pCount;
			return *this;
		}
		//转换为对象引用计数，如果没有计数则返回-1
		operator index_t()const { return pCount ? (size_t)*pCount : -1; }
		//构造
		PRefCount() :pCount(NULL) {}
		//复制构造
		PRefCount(PRefCount const&r) :pCount(r.pCount)
		{
			if (pCount)pCount->AddRef();
		}
		//赋值构造
		PRefCount& operator=(PRefCount const&r)
		{
			ChangeRef(r.pCount);
			return *this;
		}
		//改变RefCount引用
		void ChangeRef(RefCount* p)
		{
			if (pCount == p)return;
			if (pCount&&pCount->Release() == 0)delete pCount;
			if ((pCount = p)!=NULL)pCount->AddRef();
		}
		//获取弱引用计数
		index_t GetWeakRefCount()const { return pCount ? pCount->weakReferenceCount : -1; }
		//析构
		~PRefCount()
		{
			if (pCount&&pCount->Release() == 0)
			{
				delete pCount;
			}
		}
		/**
		@brief 获取该引用计数是否启用原子增减
		@return 返回值为true时表示该引用计数启用了原子增减
		@note 如果该引用为空将会抛出空指针异常*/
		inline bool GetEnableInterlocked()const { return CheckPointer<RefCount>(pCount)->GetEnableInterlocked(); }
		/**
		@brief 设置该引用计数是否使用原子增减
		@param [传入]参数b为true时表示启用原子增减
		@note 如果该引用为空将会抛出空指针异常*/
		inline void SetEnableInterlocked(bool b) { CheckPointer<RefCount>(pCount)->SetEnableInterlocked(b); }
		//指针
		mutable RefCount* pCount;
#ifdef LK_MUTEX_
	private:
		static SpinMutex& getMutexRef()
		{
			static SpinMutex* p;
			if (p)return *p;
			SpinMutex::GetDefaultRef().Lock();
			static SpinMutex m;
			p = &m;
			SpinMutex::GetDefaultRef().UnLock();
			return m;
		}
#endif
	};
}
#endif
